using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using TheGameClient.Webservices;
using Waaahsabi.Controls.DWM;
using Waaahsabi.Controls.FileSystem;
using Waaahsabi.Controls.TheGame;

namespace TheGameClient.Processes
{
	public abstract class ProgramBase : IProgram
	{
		protected IFileManager Container;
		protected EventHandler<ExecuteProgramCompletedEventArgs> ServiceCallHandler;
		protected bool OperationResult;
		protected UIElement RootObject;
		protected Guid SourceConnectionId = Guid.Empty;
		protected ulong SourceFileId;
		protected double Speed;
		private string _statusCache;
		protected Guid TargetConnectionId = Guid.Empty;
		protected ulong TargetDirectoryId;
		protected TheGameWindow TopmostWindow;

		protected ProgramBase()
		{
			Control = new GenericTargetingControl();
		}

		protected abstract bool OnlyLocal { get; }
		protected abstract string SuccessStatus { get; }
		protected abstract string FailureStatus { get; }
		protected abstract string DropErrorStatus { get; }

		#region IProgram Members

		public abstract ulong InterfaceId { get; }
		public abstract string ProcessName { get; }

		public Guid ProcessId { get; private set; }

		public InterfaceCategory Category
		{
			get { return InterfaceCategory.Program; }
		}

		public ulong ProgramId { get; set; }
		public ProgramState State { get; protected set; }
		public int Version { get; set; }
		public GenericTargetingControl Control { get; protected set; }
		public bool IsInitialized { get; protected set; }

		public virtual void Initialize()
		{
			Control.Label = string.Format("{0} v{1}.0", ProcessName, Version);
			Control.ControlMoving += OnControlMoving;
			Control.Drop += OnDrop;
			Control.QuitButtonClick += OnQuitButtonClick;
			_statusCache = Control.StatusText;
			Control.StatusText = "Initializing...";
			ProcessId = Guid.NewGuid();
			State = ProgramState.None;
			ProgramManager.Instance.RegisterProcess(this);
			Control.AnimationCompleted += OnAnimationCompleted;
			ProgramManager.Instance.GetSpeedForProcessCompleted += InstanceGetSpeedForProcessCompleted;
			ProgramManager.Instance.GetSpeed(ProcessId);
			State = ProgramState.Busy;
		}

		public virtual void Execute()
		{
			TheGameServiceClient client = App.Client;
			client.ExecuteProgramCompleted += OnServiceResult;
			client.ExecuteProgramAsync(App.InternalSessionId, ProgramId, new List<object> {SourceConnectionId, SourceFileId});
		}

		public virtual void SetOperationResult(bool successful)
		{
		}

		#endregion

		private void InstanceGetSpeedForProcessCompleted(object sender, GetSpeedEventArgs e)
		{
			IsInitialized = true;
			Speed = e.Speed;
			State = ProgramState.None;
			Control.StatusText = _statusCache;
		}

		protected virtual void OnAnimationCompleted(object sender, EventArgs e)
		{
			Execute();
			State = ProgramState.None;
		}

		protected virtual void OnControlMoving(object sender, MouseEventArgs e)
		{
			if (RootObject == null)
			{
				var controlParent = VisualTreeHelper.GetParent(Control);
				RootObject = VisualTreeHelper.GetParent(controlParent) as UIElement;
			}

			var window =
				VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), RootObject).OfType<TheGameWindow>().
					FirstOrDefault();
			TopmostWindow = window;
			if (window != null)
			{
				if (!window.IsFocused)
					window.Focus();
			}
		}

		protected virtual void OnQuitButtonClick(object sender, RoutedEventArgs e)
		{
			Control.AnimationCompleted -= OnAnimationCompleted;
			Control.InterruptAnimation();
			var controlParent = VisualTreeHelper.GetParent(Control);
			if (controlParent is Canvas)
				((Canvas) controlParent).Children.Remove(Control);
			ProgramManager.Instance.UnregisterProcess(ProcessId);
		}

		protected virtual void OnDrop(object sender, MouseButtonEventArgs e)
		{
			if (State == ProgramState.Busy)
				return;
			if (TopmostWindow == null)
				return;
			bool isLocal = false;
			GenericSystemInterface gsi =
				VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), TopmostWindow).OfType<GenericSystemInterface>().
					FirstOrDefault();
			if (gsi == null)
				//no generic system interface found, thus we are either in a local filemanager, or something is wrong
			{
				GatewayFileManager gfm =
					VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), TopmostWindow).OfType<GatewayFileManager>().
						FirstOrDefault();
				if (gfm == null)
					return;
				isLocal = true;
			}

			if (!isLocal)
			{
				if (OnlyLocal)
				{
					Control.StatusText = DropErrorStatus;
					return;
				}
				SourceConnectionId = gsi.ConnectionId;
			}
			else
				SourceConnectionId = Guid.Empty;

			Container =
				VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), TopmostWindow).OfType<IFileManager>().
					FirstOrDefault();
			if (Container == null)
				return;

			IFileItem sourceFile =
				VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), TopmostWindow).OfType<IFileItem>().
					FirstOrDefault();
			if (sourceFile != null)
			{
				SourceFileId = sourceFile.FileId;
				Control.Cursor = Cursors.Wait;
				Control.ShowProgressAnimation(Speed);
			}
		}

		protected virtual void OnServiceResult(object sender, ExecuteProgramCompletedEventArgs e)
		{
			App.Client.ExecuteProgramCompleted -= OnServiceResult;
			Control.InterruptAnimation();
			State = ProgramState.None;
			Control.Cursor = Cursors.Arrow;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result)
			{
				Control.StatusText = SuccessStatus;
				if (Container != null)
					Container.RefreshContent();
			}
			else
			{
				Control.StatusText = FailureStatus;
			}
		}
	}
}